﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace DARE
{
    /// <summary>
    /// This is a textbox which displays a text regarding its size.
    /// </summary>
    [AttrTypeDependentSerializable(typeof(CTextBoxData))]
    public class CTextBox : CWidget
    {
        #region fields

        public bool m_readOnly;
        private StringBuilder m_textBuilder;
        private Vector2 m_cursorPosition;
        private Vector2 m_startPosition;
        private float m_textHeight;
        private float m_textWidth;

        public bool m_HorizontalScrollBarEnabled = false;
        public bool m_VerticalScrollBarEnabled = true;

        private SpriteFont m_spriteFont;
        private float m_scale;
        public Vector2 m_textPos;
        private string m_text;
        private List<string> m_lines;

        #endregion

        #region properties

          public override Vector2 Position
        {
            get
            {
                return base.Position;
            }
            set
            {
                base.Position = value;
                m_lines.Clear();
                m_textBuilder.Remove(0, m_textBuilder.Length);
                formatLine();
                m_textToDisplay();
            }
        }

        public override Vector2 Size
        {
            get
            {
                return base.Size;
            }
            set
            {
                base.Size = value;
                m_lines.Clear();
                m_textBuilder.Remove(0, m_textBuilder.Length);
                formatLine();
                m_textToDisplay();
            }
        }

        public override Rectangle Rect
        {
            get
            {
                return base.Rect;
            }
            set
            {
                base.Rect = value;
                m_lines.Clear();
                m_textBuilder.Remove(0, m_textBuilder.Length);

                formatLine();
                m_textToDisplay();
            }
        }

        private int findMaxSize(string line, int startIndex)
        {
            int i = line.IndexOf(' ', startIndex);
            if (i < 0)
                i = line.IndexOf('\n');
            if (i < 0)
                i = line.Length;

            for (; i > startIndex; --i)
            {
                int tmp = i;
                if (tmp < startIndex)
                    tmp = startIndex;
                if (m_spriteFont.MeasureString(line.Substring(startIndex, i - startIndex)).X <= m_rect.Width)
                    return tmp - startIndex + 1;
            }
            return 0;
        }

        private void formatLine()
        {
            int lastBN = 0;
            int lastSpace = 0;
            float sizeX;
            if (m_spriteFont.MeasureString(m_text).X < m_rect.Width)
            {
                m_lines.Add(m_text);
                return;
            }
            for (int i = 0; i < m_text.Length; ++i)
            {
                if (m_text[i] == ' ' || m_text[i] == '\t')
                    lastSpace = i;
                sizeX = m_spriteFont.MeasureString(m_text.Substring(lastBN, i - lastBN).TrimEnd()).X;
                if (!m_HorizontalScrollBarEnabled && sizeX > m_rect.Width)
                {
                    if (lastBN != lastSpace)
                    {
                        m_lines.Add(m_text.Substring(lastBN, lastSpace - lastBN).TrimEnd());
                        lastBN = lastSpace;
                    }
                    else
                    {
                        m_lines.Add(m_text.Substring(lastBN, findMaxSize(m_text, i)).TrimEnd() + "...");
                        lastBN = m_text.IndexOf(" ", i);
                        int tmp = m_text.IndexOf("\n", i);
                        if (tmp < lastBN && tmp >= 0)
                            lastBN = tmp;
                        lastSpace = lastBN;
                    }
                    i = lastBN;
                    m_textWidth = m_rect.Width;
                }
                else if (m_text[i] == '\n')
                {
                    m_lines.Add(m_text.Substring(lastBN, i - lastBN).TrimEnd());
                    lastBN = i + 1;
                    lastSpace = i + 1;
                }
            }
            m_lines.Add(m_text.Substring(lastBN, m_text.Length - lastBN).TrimEnd());
            if (m_HorizontalScrollBarEnabled)
            {
                float max = 0;
                foreach (string line in m_lines)
                {
                    sizeX = m_spriteFont.MeasureString(line).X;
                    if (sizeX > max)
                        max = sizeX;
                }
                m_textWidth = max;
            }

        }

        public string TextToDisplay
        {
            get { return m_textBuilder.ToString(); }
        }

        public string Text
        {
            get { return m_text; }
            set
            {
                m_text = value;
                m_lines.Clear();
                m_textBuilder.Remove(0, m_textBuilder.Length);
                if (m_text != "" && m_text != null)
                {
                    formatLine();
                    m_textToDisplay();
                }
            }
        }

        public SpriteFont Font { get { return m_spriteFont; } set { m_spriteFont = value; } }
        public float Scale { get { return m_scale; } set { m_scale = value; } }

        #endregion

        #region m_textToDisplay

        public void m_textToDisplay()
        {
            float height = m_spriteFont.MeasureString("|").Y;
            m_textHeight = height * m_lines.Count;
            int i = 0;
            m_textBuilder.Remove(0, m_textBuilder.Length);
            foreach (string line in m_lines)
            {
                ++i;
                if (i * height >= m_rect.Height)
                    break;
                if (line.Contains("\n"))
                    m_textBuilder.AppendLine(line.Substring(0, line.Length - 1) + " ");
                else
                    m_textBuilder.AppendLine(line);
            }
        }

        #endregion

        #region ctor

        public CTextBox(CHUDSystem hud, CWidget parent, string name)
            : base(hud, parent, name)
        {
            m_lines = new List<string>();
            m_textBuilder = new StringBuilder();
            m_text = "";
            m_cursorPosition = Vector2.Zero;
            m_startPosition = Vector2.Zero;
            m_readOnly = false;
            m_scale = 1;
            m_textPos = Vector2.Zero;
            m_spriteFont = HUD.Skinner.GetSpriteFont("textboxdefault");
            Size = new Vector2(300, 300);
        }

        #endregion

        #region events
/*
        public Vector2 getCursorPosition(MouseState mouse)
        {
            int posY;
            int posX;
            float lineHeight = (m_spriteFont.MeasureString("|\n|").Y / 2.0f);


            posY = (int)((float)(mouse.Y - m_rect.Y) / lineHeight);
            if (posY < 0)
                posY = 0;
            if (m_lines.Count < posY)
                return new Vector2(m_lines[m_lines.Count - 1].Length, m_lines.Count - 1);
            posX = (int)(mouse.X - m_rect.X);
            for (int i = 1; i < m_lines[posY].Length; ++i)
            {
                if (m_spriteFont.MeasureString(m_lines[posY].Substring(0, i - 1)).X < posX && m_spriteFont.MeasureString(m_lines[posY].Substring(0, i)).X > posX)
                {
                    posX = i - 1;
                    break;
                }
            }

            if (posX == (int)(mouse.X - m_rect.X))
                posX = m_lines[posY].Length;
            return new Vector2(posX, posY);
        }

        public Vector2 getCursorPosition(Vector2 relativePos)
        {
            Vector2 absPos = new Vector2();

            absPos.Y = ((float)(relativePos.Y * (m_spriteFont.MeasureString("|\n|").Y) / 2.0f) / (float)rect.Height);
            absPos.X = ((float)m_spriteFont.MeasureString(m_lines[(int)relativePos.Y].Substring(0, (int)relativePos.X)).X) / (float)rect.Width;

            return absPos;
        }

        public override bool onClick(MouseState mouse)
        {
            mouseState = mouse;
            isClicked = true;
            m_cursorPosition = getCursorPosition(mouse);
            isSelectionMode = false;

            return true;//base.onClick(mouse);
        }

        public override bool onRelease(MouseState mouse)
        {
            isClicked = false;
            if (!isSelectionMode)
            {
                isCursorVisible = true;
                cursor.Position = getCursorPosition(m_cursorPosition);
            }
            else
                isCursorVisible = false;

            return true;//base.onRelease(mouse);
        }

        */
        #endregion

        #region draw / update
        
        public override bool Update(GameTime gameTime)
        {
            if (!m_isVisible)
                return false;
            return base.Update(gameTime);
        }

        public override bool Draw(GameTime gameTime)
        {
            if (!m_isVisible)
                return false;
            if (this.m_texture != null)
                m_texture.Draw(gameTime);// m_spriteBatch.Draw(this.m_texture, this.m_rect, m_color);

            m_textPos = new Vector2(m_rect.X, m_rect.Y);
            SpriteBatch.DrawString(m_spriteFont, m_textBuilder, m_textPos + new Vector2(m_margins.Left, m_margins.Top), Color, 0.0f, Vector2.Zero, m_scale, SpriteEffects.None, 0);
            foreach (CWidget child in m_children.Values)
                child.Draw(gameTime);
            return true;
        }

        #endregion
    }
}
